package org.extreme.pivot.grid;

import org.apache.pivot.wtk.Bounds;
import org.apache.pivot.wtk.Component;
import org.apache.pivot.wtk.Mouse;
import org.apache.pivot.wtk.Orientation;
import org.apache.pivot.wtk.ScrollBar;
import org.apache.pivot.wtk.ScrollBarValueListener;
import org.apache.pivot.wtk.Viewport;
import org.apache.pivot.wtk.ViewportListener;
import org.apache.pivot.wtk.Viewport.Skin;
import org.apache.pivot.wtk.skin.ContainerSkin;
import org.extreme.pivot.editor.CellEditor;

public class XSheetPaneSkin extends ContainerSkin 
							implements Skin, ScrollBarValueListener, ViewportListener, XSheetPane.Skin {
	private static final int DEFAULT_HORIZONTAL_INCREMENT = 1;
    private static final int DEFAULT_VERTICAL_INCREMENT = 1;
	
	private ScrollBar horizontalScrollBar = new ScrollBar(Orientation.HORIZONTAL);
	private ScrollBar verticalScrollBar = new ScrollBar(Orientation.VERTICAL);
	
	private int editCol = -1;
	private int editRow = -1;
	
	public XSheetPaneSkin() {
		horizontalScrollBar.setUnitIncrement(DEFAULT_HORIZONTAL_INCREMENT);
		verticalScrollBar.setUnitIncrement(DEFAULT_VERTICAL_INCREMENT);
	}
	
	@Override
	public Bounds getViewportBounds() {
		int x = 0;
        int y = 0;
        int width = getWidth();
        int height = getHeight();

        XSheetPane xSheetPane = (XSheetPane)getComponent();

        GridRow gridRow = xSheetPane.getGridRow();
        if (gridRow != null) {
            int rowHeaderWidth = gridRow.getWidth();

            x += rowHeaderWidth;
            width -= rowHeaderWidth;
        }

        GridColumn gridColumn = xSheetPane.getGridColumn();
        if (gridColumn != null) {
            int columnHeaderHeight = gridColumn.getHeight();

            y += columnHeaderHeight;
            height -= columnHeaderHeight;
        }

        if (horizontalScrollBar.isVisible()) {
            height -= horizontalScrollBar.getHeight();
        }

        if (verticalScrollBar.isVisible()) {
            width -= verticalScrollBar.getWidth();
        }

        return new Bounds(x, y, width, height);
	}

	@Override
	public void layout() {
		XSheetPane xSheetPane = (XSheetPane)getComponent();
		
		int width = getWidth();
		int height = getHeight();

		Grid grid = (Grid)xSheetPane.getView();
		GridRow gridRow = xSheetPane.getGridRow();
		GridColumn gridColumn = xSheetPane.getGridColumn();
		GridCorner gridCorner = xSheetPane.getGridCorner();
		
		int gridRowWidth = 0;
		if (gridRow != null) {
			gridRowWidth = gridRow.getPreferredWidth(-1);
		}
		
		int gridColumnHeight = 0;
		if (gridColumn != null) {
			gridColumnHeight = gridColumn.getPreferredHeight(-1);
		}
		
        int horizontalScrollBarHeight = horizontalScrollBar.getPreferredHeight(-1);
        int verticalScrollBarWidth = verticalScrollBar.getPreferredWidth(-1);
        
        int viewWidth = Math.max(width - gridRowWidth - verticalScrollBarWidth, 0);
        int viewHeight = Math.max(height - gridColumnHeight - horizontalScrollBarHeight, 0);
        
        if (grid != null) {
        	grid.setSize(viewWidth, viewHeight);
        	grid.setLocation(gridRowWidth, gridColumnHeight);
        }

        if (gridColumn != null) {
        	gridColumn.setSize(viewWidth, gridColumnHeight);
        	gridColumn.setLocation(gridRowWidth, 0);
        }

        if (gridRow != null) {
        	gridRow.setSize(gridRowWidth, viewHeight);
        	gridRow.setLocation(0, gridColumnHeight);
        }
        
        if (gridRowWidth > 0 && gridColumnHeight > 0) {
        	gridCorner.setSize(gridRowWidth, gridColumnHeight);
        	gridCorner.setLocation(0, 0);
        }
        
        if (horizontalScrollBarHeight > 0) {
        	horizontalScrollBar.setVisible(true);
        	int horizontalScrollBarWidth = Math.max(width - gridRowWidth - verticalScrollBarWidth, 0);
        	horizontalScrollBar.setSize(horizontalScrollBarWidth, horizontalScrollBarHeight);
            horizontalScrollBar.setLocation(gridRowWidth, height - horizontalScrollBarHeight);
        } else {
        	horizontalScrollBar.setVisible(false);
        }
        
        if (verticalScrollBarWidth > 0) {
            verticalScrollBar.setVisible(true);

            int verticalScrollBarHeight = Math.max(height - gridColumnHeight - horizontalScrollBarHeight, 0);
            verticalScrollBar.setSize(verticalScrollBarWidth, verticalScrollBarHeight);
            verticalScrollBar.setLocation(width - verticalScrollBarWidth, 0);
        }
        
		int sum = 0;
		
		int endCol = xSheetPane.getScrollLeft();
		for (; endCol < xSheetPane.lastCol && sum < viewWidth; endCol ++) {
			sum += xSheetPane.colWidthList.get(endCol);
		}
		
		xSheetPane.scrollRight = endCol;
		
		if (endCol >= xSheetPane.lastCol) {
			xSheetPane.lastCol ++;
		}
		
		horizontalScrollBar.setScope(0, xSheetPane.lastCol, endCol - xSheetPane.getScrollLeft());
		
		sum = 0;
		
		int endRow = xSheetPane.getScrollTop();
		for (; endRow < xSheetPane.lastRow && sum < viewHeight; endRow ++) {
			sum += xSheetPane.rowHeightList.get(endRow);
		}
		
		if (endRow >= xSheetPane.lastRow) {
			xSheetPane.lastRow ++;
		}
		
		xSheetPane.scrollBottom = endRow;
		
		verticalScrollBar.setScope(0, xSheetPane.lastRow, endRow - xSheetPane.getScrollTop());
	}
	
	@Override
	public void install(Component component) {
		super.install(component);
		
		XSheetPane xSheetPane = (XSheetPane)component;
		
		xSheetPane.getViewportListeners().add(this);
		
		xSheetPane.add(horizontalScrollBar);
		xSheetPane.add(verticalScrollBar);
		
		horizontalScrollBar.getScrollBarValueListeners().add(this);
		verticalScrollBar.getScrollBarValueListeners().add(this);
	}
	
	@Override
    public boolean mouseDown(Component component, Mouse.Button button, int x, int y) {
		boolean consumed = super.mouseDown(component, button, x, y);
		
		editCol = getColAt(x);
		editRow = getRowAt(y);
		
		return consumed;
	}
	
	@Override
    public boolean mouseClick(Component component, Mouse.Button button, int x, int y, int count) {
        boolean consumed = super.mouseClick(component, button, x, y, count);

        XSheetPane xSheetPane = (XSheetPane)getComponent();
        if (editCol != -1 && editRow != -1
            && count == 2) {
        	CellEditor cellEditor = xSheetPane.getCellEditor(editCol, editRow);

            if (cellEditor != null
                && !cellEditor.isEditing()) {
                //cellEditor.
            	System.out.println("cellEditor.startEditing()...at:" + editCol + "," + editRow );
            	cellEditor.editCell(xSheetPane, editCol, editRow);
            }
        }

        editCol = -1;
        editRow = -1;

        return consumed;
    }

	@Override
	public void valueChanged(ScrollBar scrollBar, int previousValue) {
		XSheetPane xSheetPane = (XSheetPane)getComponent();

        int value = scrollBar.getValue();

        if (scrollBar == horizontalScrollBar) {
            xSheetPane.setScrollLeft(value);
        } else {
            xSheetPane.setScrollTop(value);
        }
		
	}

	@Override
	public void scrollLeftChanged(Viewport scrollPane, int previousScrollLeft) {
//		XSheetPane xSheetPane = (XSheetPane)getComponent();
		invalidateComponent();
	}

	@Override
	public void scrollTopChanged(Viewport scrollPane, int previousScrollTop) {
		invalidateComponent();
	}

	@Override
	public void viewChanged(Viewport scrollPane, Component previousView) {
		
	}

	public int getRowAt(int y) {
		XSheetPane xSheetPane = (XSheetPane)getComponent();
		Grid grid = (Grid)xSheetPane.getView();
		y = y - grid.getY();
		return grid.getRowAt(y);
	}
	
	public int getColAt(int x) {
		XSheetPane xSheetPane = (XSheetPane)getComponent();
		Grid grid = (Grid)xSheetPane.getView();
		x = x - grid.getX();
		return grid.getColAt(x);
	}

	@Override
	public Bounds getCellBounds(int col, int row) {
		XSheetPane xSheetPane = (XSheetPane)getComponent();
		
		Grid grid = (Grid)xSheetPane.getView();
		Bounds gridBounds = grid.getCellBounds(col, row);
        
		return new Bounds(gridBounds.x + grid.getX(), gridBounds.y + grid.getY(), gridBounds.width, gridBounds.height);
	}
}
